package com.mysen.sso.aop;

import static com.mysen.sso.util.ValidationConfig.DEFAULT_CHECKFOR_ANNOTATION;
import static com.mysen.sso.util.ValidationConfig.DEFAULT_USER_CHECK;
import static com.mysen.sso.util.ValidationConfig.KEY__BRIDGEBEANNAME;
import static com.mysen.sso.util.ValidationConfig.KEY__CHECKFORANNOTATION;
import static com.mysen.sso.util.ValidationConfig.KEY__USERCHECK;
import static com.mysen.sso.util.ValidationConfig.getValidationConfig;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.mysen.exception.MaikeServiceException;
import com.mysen.json.JSONArray;
import com.mysen.json.JSONEnv;
import com.mysen.json.JSONFunc;
import com.mysen.json.JSONObject;
import com.mysen.model.Response;
import com.mysen.spring.plugin.WebContextUtil;
import com.mysen.sso.util.ValidationConfig;

@Deprecated
@Aspect
public class ParamValidateAopAction {

    private static final Logger LOGGER = LoggerFactory.getLogger(ParamValidateAopAction.class);

    @Pointcut("execution(* com.maike.sso.controller..*.*(..))")
    private void controllerAspect(){}
    
    @Autowired
    private WebApplicationContext context;
	/**
     * 方法执行
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        //日志实体对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String uri = WebContextUtil.getUri(request);
        String reqMethod = request.getMethod();
        String sid = WebContextUtil.getSid(request);
        
        LOGGER.info("request {}:{} start valid...", reqMethod, uri);
        
        Response<Object> resp = null;
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sid", sid);
        resp = validateUserCheck(uri, reqMethod, map);
        if(resp != null){
        	LOGGER.warn("validation {} validate not pass{}:{} ... ", KEY__USERCHECK, reqMethod, uri);
        	resp.setErrorMsg("UNAUTHORIZED");
        	return resp;
        }
        
        Map<String,Object> parameters = getParammeterMap(uri, pjp);
        resp = validateParameters(uri, reqMethod, parameters);
        if(resp != null){
        	resp.setErrorMsg("BAD_REQUEST");
        	return resp;
        }
        
		LOGGER.info("validation validate pass...");
        return pjp.proceed();
    }
    
    /**
     * 验证参数体
     * */
	private Response<Object> validateParameters(String uri, String reqMethod, Map<String, Object> parameters) {
		Response<Object> resp = null;
		JSONObject config = getValidationConfig(uri, reqMethod);
		JSONArray errors = new JSONArray();
		String bridgeBeanName = getValidationConfig(uri, ValidationConfig.KEY__BRIDGEBEANNAME);
		bridgeBeanName = bridgeBeanName == null ? "paramCheckJSONBridge" : bridgeBeanName;
		Object bridge = context.getBean(bridgeBeanName);
		
		if(!ValidationConfig.validate(config, parameters, errors, bridge)){
			LOGGER.warn("validation validate not pass... ");
			resp = new Response<>();
			resp.setSuccess(false);
			resp.setData(errors);
        	resp.setErrorMsg("VALIDATION_NOT_PASS");
			return resp;
		}
		return resp;
	}
	
	/**
	 * 获取切面方法参数
	 * 存在注解标记的参数封装并返回
	 * @RequestBody注解标记的参数 key 为null
	 * */
	private Map<String,Object> getParammeterMap(String uri, ProceedingJoinPoint pjp)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		Map<String,Object> params = new HashMap<>();

        // 拦截的方法参数
        Object[] args = pjp.getArgs();
        if(args == null || args.length == 0)
        	return params;
        
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        
		Parameter[] parameters = msig.getMethod().getParameters();
        for(int i = 0; i < parameters.length; i++) {
        	Parameter p = parameters[i];
        	Object obj = args[i];
        	JSONObject annotationObj = getValidationConfig(uri, KEY__CHECKFORANNOTATION);
        	JSONArray annotations = DEFAULT_CHECKFOR_ANNOTATION;
        	if(annotationObj != null) {
        		annotations = annotationObj.getJSONArray(KEY__CHECKFORANNOTATION, DEFAULT_CHECKFOR_ANNOTATION);
        	}
        	Annotation annotation = getExistAnnotation(p, annotations);
        	if(annotation != null) {
        		String key = null;
        		if(!(annotation instanceof RequestBody)) {
        			Method me = annotation.getClass().getDeclaredMethod("value");
        			key = (String)me.invoke(annotation);
        		}
        		params.put(key, obj);
        	}
        }
        return params;
	}
	
	/**
	 * 验证用户登录信息
	 * */
	private Response<Object> validateUserCheck(String uri, String reqMethod, Map<String,Object> map) {
		Object obj = getValidationConfig(uri, KEY__USERCHECK);
		if(obj == null) {
			return null;
		}
		JSONObject userCheckObj = null;
		if(obj instanceof JSONObject) {
			userCheckObj = (JSONObject)obj;
		}else if(obj instanceof JSONFunc) {
			userCheckObj = new JSONObject();
			userCheckObj.put(reqMethod, obj);
		}else {
			throw new MaikeServiceException("not support type:" + (obj != null ? obj.getClass() : "null"));
		}
        JSONFunc func = DEFAULT_USER_CHECK;
        if(userCheckObj != null) {
        	func = userCheckObj.getJSONFunc(reqMethod, DEFAULT_USER_CHECK);
        }
        map.put("this", userCheckObj);
        
        String bridgeName = getValidationConfig(uri, KEY__BRIDGEBEANNAME);
        bridgeName = StringUtils.hasText(bridgeName) ? bridgeName.trim() : "paramCheckJSONBridge";
        
        JSONEnv env = new JSONEnv(map, context.getBean(bridgeName));
        Boolean b = (Boolean)func.exec(env);
        if(!b) {
        	Response<Object> resp = new Response<>();
        	resp.setSuccess(false);
        	resp.setData(HttpStatus.UNAUTHORIZED.getReasonPhrase());
        	return resp;
        }
		return null;
	}
	/**
	 * 获取Controller 参数的注解
	 * */
	private Annotation getExistAnnotation(Parameter p, JSONArray annotations) {
		for(int i=0;i<annotations.size();i++) {
			String annotationName = annotations.getString(i);
			try {
				@SuppressWarnings("unchecked")
				Class<Annotation> name = (Class<Annotation>) Class.forName(annotationName);
				Annotation annotation = p.getAnnotation(name);
				if(annotation != null)
					return annotation;
			} catch (ClassNotFoundException e) {
				throw new MaikeServiceException(e);
			}
		}
		return null;
	}
}